#!/bin/sh

APP_ROOT="/var/www/html"
PHP_INI_TEMPLATE="/etc/his/php.ini.template"
PHP_INI_TARGET="/usr/local/etc/php/conf.d/99-his.ini"
PHP_FPM_TEMPLATE="/etc/his/php-fpm.conf.template"
PHP_FPM_TARGET="/usr/local/etc/php-fpm.d/zz-his.conf"
NGINX_TEMPLATE="/etc/his/nginx.conf.template"
NGINX_TARGET_ALPINE="/etc/nginx/http.d/default.conf"
NGINX_TARGET_DEBIAN="/etc/nginx/conf.d/default.conf"
SUPERVISOR_LOG_DIR="/var/log/supervisor"
NGINX_LOG_DIR="/var/log/nginx"

log() {
  printf '[entrypoint] %s\n' "$*"
}

ensure_templates() {
  local vars="\$PHP_MEMORY_LIMIT \$PHP_MAX_EXECUTION_TIME \$PHP_UPLOAD_MAX_FILESIZE \$PHP_POST_MAX_SIZE \$TZ"
  envsubst "$vars" < "${PHP_INI_TEMPLATE}" > "${PHP_INI_TARGET}"
  envsubst "$vars" < "${PHP_FPM_TEMPLATE}" > "${PHP_FPM_TARGET}"
  # Write Nginx config for both Alpine and Debian layout
  if [ -d "/etc/nginx/http.d" ]; then
    envsubst "$vars" < "${NGINX_TEMPLATE}" > "${NGINX_TARGET_ALPINE}"
  fi
  if [ -d "/etc/nginx/conf.d" ]; then
    envsubst "$vars" < "${NGINX_TEMPLATE}" > "${NGINX_TARGET_DEBIAN}"
    # Disable Debian's default site to avoid duplicate default_server
    if [ -e "/etc/nginx/sites-enabled/default" ]; then
      rm -f /etc/nginx/sites-enabled/default
    fi
  fi
}

ensure_env() {
  if [ ! -f "${APP_ROOT}/.env" ] && [ -f "${APP_ROOT}/.env.example" ]; then
    log "Creating .env from .env.example"
    cp "${APP_ROOT}/.env.example" "${APP_ROOT}/.env"
  fi

  # Ensure .env has APP_KEY entry
  if ! grep -q '^APP_KEY=' "${APP_ROOT}/.env"; then
    printf '\nAPP_KEY=\n' >> "${APP_ROOT}/.env"
  fi

  # Prefer external APP_KEY if provided
  if [ -n "${APP_KEY:-}" ]; then
    sed -i "s#^APP_KEY=.*#APP_KEY=${APP_KEY}#g" "${APP_ROOT}/.env"
  fi

  # If APP_KEY is still empty, generate a key proactively
  CURRENT_KEY=$(grep -E '^APP_KEY=' "${APP_ROOT}/.env" | sed 's/^APP_KEY=//')
  if [ -z "${CURRENT_KEY}" ]; then
    NEW_KEY=$(php -r 'echo "base64:".base64_encode(random_bytes(32));')
    sed -i "s#^APP_KEY=.*#APP_KEY=${NEW_KEY}#g" "${APP_ROOT}/.env"
    export APP_KEY="${NEW_KEY}"
    log "APP_KEY generated"
  else
    export APP_KEY="${CURRENT_KEY}"
  fi
}

run_artisan() {
  if command -v su-exec >/dev/null 2>&1; then
    su-exec app:app php artisan "$@"
  elif command -v gosu >/dev/null 2>&1; then
    gosu app:app php artisan "$@"
  else
    php artisan "$@"
  fi
}

run_artisan_safe() {
  if command -v su-exec >/dev/null 2>&1; then
    su-exec app:app env \
      DB_HOST=${DB_RUNTIME_HOST:-${DB_HOST:-mysql}} \
      DB_PORT=${DB_PORT:-3306} \
      DB_DATABASE=${DB_DATABASE:-saas} \
      DB_USERNAME=${DB_USERNAME:-root} \
      DB_PASSWORD=${DB_PASSWORD:-} \
      CACHE_DRIVER=file \
      SESSION_DRIVER=file \
      QUEUE_CONNECTION=sync \
      BROADCAST_DRIVER=log \
      php artisan "$@"
  elif command -v gosu >/dev/null 2>&1; then
    gosu app:app env \
      DB_HOST=${DB_RUNTIME_HOST:-${DB_HOST:-mysql}} \
      DB_PORT=${DB_PORT:-3306} \
      DB_DATABASE=${DB_DATABASE:-saas} \
      DB_USERNAME=${DB_USERNAME:-root} \
      DB_PASSWORD=${DB_PASSWORD:-} \
      CACHE_DRIVER=file \
      SESSION_DRIVER=file \
      QUEUE_CONNECTION=sync \
      BROADCAST_DRIVER=log \
      php artisan "$@"
  else
    DB_HOST=${DB_RUNTIME_HOST:-${DB_HOST:-mysql}} DB_PORT=${DB_PORT:-3306} DB_DATABASE=${DB_DATABASE:-saas} DB_USERNAME=${DB_USERNAME:-root} DB_PASSWORD=${DB_PASSWORD:-} CACHE_DRIVER=file SESSION_DRIVER=file QUEUE_CONNECTION=sync BROADCAST_DRIVER=log php artisan "$@"
  fi
}

ensure_permissions() {
  chown -R app:app "${APP_ROOT}/storage" "${APP_ROOT}/bootstrap/cache"
  chown -R redis:redis /var/lib/redis
  # Ensure static assets under public/dist are readable by nginx (www-data)
  if [ -d "${APP_ROOT}/public/dist" ]; then
    find "${APP_ROOT}/public/dist" -type d -exec chmod 755 {} + 2>/dev/null || true
    find "${APP_ROOT}/public/dist" -type f -exec chmod 644 {} + 2>/dev/null || true
  fi
  # Ensure Laravel storage structure exists
  mkdir -p "${APP_ROOT}/storage/framework/cache" \
           "${APP_ROOT}/storage/framework/sessions" \
           "${APP_ROOT}/storage/framework/views" \
           "${APP_ROOT}/storage/logs"
  chown -R app:app "${APP_ROOT}/storage" "${APP_ROOT}/bootstrap/cache"
}

sanitize_central_domain() {
  if [ "${SANITIZE_CENTRAL_DOMAIN:-true}" != "true" ]; then
    return 0
  fi
  log "Sanitizing central_domain (strip port if present)"
  cat > /tmp/sanitize_domain.php <<'PHP'
<?php
require 'vendor/autoload.php';
$app = require 'bootstrap/app.php';
$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
try {
  $val = \Illuminate\Support\Facades\DB::table('cy_admin_parameters')->where('name','central_domain')->value('value');
  if ($val) {
    $url = (strpos($val, '://') === false ? ('http://' . $val) : $val);
    $host = parse_url($url, PHP_URL_HOST);
    if ($host && $host !== $val) {
      \Illuminate\Support\Facades\DB::table('cy_admin_parameters')->where('name','central_domain')->update(['value'=>$host]);
      \Illuminate\Support\Facades\Cache::forget('admin_parameters');
    }
  }
} catch (\Throwable $e) { /* ignore */ }
PHP
  su-exec app:app php /tmp/sanitize_domain.php >/dev/null 2>&1 || true
}

ensure_install_lock() {
  if [ "${AUTO_INSTALL_LOCK:-true}" != "true" ]; then
    return 0
  fi
  if [ -f "${APP_ROOT}/storage/install.lock" ]; then
    return 0
  fi
  log "Checking install state to create install.lock if ready"
  cat > /tmp/ensure_lock.php <<'PHP'
<?php
require 'vendor/autoload.php';
$app = require 'bootstrap/app.php';
$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
try {
  $db = app('db');
  $schema = $db->getSchemaBuilder();
  if ($schema->hasTable('cy_admins') && $schema->hasTable('cy_admin_parameters')) {
    @mkdir('storage', 0775, true);
    file_put_contents('storage/install.lock', time());
  }
} catch (\Throwable $e) { /* ignore */ }
PHP
  su-exec app:app php /tmp/ensure_lock.php >/dev/null 2>&1 || true
}

bootstrap_app() {
  ensure_templates
  ensure_env
  ensure_permissions

  if [ "${WAIT_FOR_DB:-true}" = "true" ]; then
    DB_HOST=${DB_HOST:-mysql}
    DB_PORT=${DB_PORT:-3306}
    PROBE_HOST=${DB_HOST}
    case "${DB_HOST}" in
      127.0.0.1|localhost)
        PROBE_HOST=mysql
        ;;
    esac
    DB_WAIT_TIMEOUT=${DB_WAIT_TIMEOUT:-120}
    export DB_RUNTIME_HOST="${PROBE_HOST}"
    log "Waiting for database ${PROBE_HOST}:${DB_PORT} (timeout ${DB_WAIT_TIMEOUT}s)"
    DB_WAIT_ELAPSED=0
    until nc -z "${PROBE_HOST}" "${DB_PORT}"; do
      sleep 2
      DB_WAIT_ELAPSED=$((DB_WAIT_ELAPSED + 2))
      if [ "${DB_WAIT_ELAPSED}" -ge "${DB_WAIT_TIMEOUT}" ]; then
        log "Database connection timed out"
        exit 1
      fi
    done
  fi

  # fix central_domain before any caching
  sanitize_central_domain
  ensure_install_lock

  if [ "${RUN_STORAGE_LINK:-true}" = "true" ]; then
    if ! run_artisan storage:link >/dev/null 2>&1; then
      log "storage:link skipped (already exists or failed silently)"
    else
      log "storage symlink created"
    fi
  fi

  if [ -z "${APP_KEY:-}" ]; then
    if ! grep -q '^APP_KEY=' "${APP_ROOT}/.env" || grep -q '^APP_KEY=$' "${APP_ROOT}/.env"; then
      log "Generating APP_KEY"
      run_artisan key:generate --force
    fi
  fi

  # Ensure APP_KEY is present in process env for config:cache
  if [ -z "${APP_KEY:-}" ]; then
    APP_KEY=$(grep -E '^APP_KEY=' "${APP_ROOT}/.env" | sed 's/^APP_KEY=//')
    export APP_KEY
    log "Exported APP_KEY from .env: ${APP_KEY%%=*}"
  fi

  if [ "${RUN_MIGRATIONS:-true}" = "true" ]; then
    log "Running database migrations"
    # ensure no cached config forces redis connection
    run_artisan_safe config:clear || true
    run_artisan_safe migrate --force
    # Ensure admin schema exists and default admin user created (via PHP script)
    cat > /tmp/ensure_admin.php <<'PHP'
<?php
require 'vendor/autoload.php';
$app = require 'bootstrap/app.php';
$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$db = $app->make('db');
$schema = $db->connection()->getSchemaBuilder();
if (!$schema->hasTable('cy_admins')) {
  \Illuminate\Support\Facades\Artisan::call('migrate', ['--path'=>'database/migrations/admin', '--force'=>true]);
}
try { $count = (int) $db->table('cy_admins')->count(); } catch (\Throwable $e) { $count = 0; }
if ($count === 0) {
  $u = getenv('INIT_ADMIN_USERNAME') ?: 'admin';
  $p = getenv('INIT_ADMIN_PASSWORD') ?: '12345678';
  $model = new \App\Models\Admin\Admin();
  $model->name = '管理员';
  $model->email = $u;
  $model->password = password_hash($p, PASSWORD_BCRYPT);
  $model->save();
}
PHP
    su-exec app:app php /tmp/ensure_admin.php >/dev/null 2>&1 || true
  else
    log "Skipping automatic migrations"
  fi

  if [ "${RUN_CACHE_WARMUP:-true}" = "true" ]; then
    log "Warming up Laravel caches"
    run_artisan_safe config:clear || true
    run_artisan_safe route:clear || true
    run_artisan_safe view:clear || true
    if [ -f "${APP_ROOT}/storage/install.lock" ]; then
      run_artisan_safe config:cache
      run_artisan_safe route:cache
      run_artisan_safe view:cache || log "view:cache failed; continuing"
    else
      log "Install lock not found; skip route/config cache to avoid forcing installer"
    fi
    # Fallback: ensure APP_KEY present in cached config
    if [ -f "${APP_ROOT}/bootstrap/cache/config.php" ]; then
      KEY_LINE=$(grep -E '^APP_KEY=' "${APP_ROOT}/.env" | sed 's/^APP_KEY=//')
      if [ -n "${KEY_LINE}" ]; then
        sed -i "s/'key' => ''/'key' => '${KEY_LINE//\//\\\/}'/" "${APP_ROOT}/bootstrap/cache/config.php" || true
      fi
    fi
  fi
}

start_supervisor() {
  mkdir -p "${SUPERVISOR_LOG_DIR}" "${NGINX_LOG_DIR}"
  chown -R app:app "${SUPERVISOR_LOG_DIR}" "${NGINX_LOG_DIR}"
  # Ensure Debian default site is disabled
  if [ -e "/etc/nginx/sites-enabled/default" ]; then
    rm -f /etc/nginx/sites-enabled/default
  fi
  exec supervisord -c /etc/supervisor/conf.d/supervisord.conf
}

case "${1:-start}" in
  start)
    bootstrap_app
    start_supervisor
    ;;
  queue)
    shift
    bootstrap_app
    exec su-exec app:app php artisan queue:work --verbose --timeout=90 --tries=3 "$@"
    ;;
  scheduler)
    shift
    bootstrap_app
    exec su-exec app:app php artisan schedule:work "$@"
    ;;
  artisan)
    shift
    bootstrap_app
    exec su-exec app:app php artisan "$@"
    ;;
  bash)
    shift
    bootstrap_app
    exec /bin/sh "$@"
    ;;
  *)
    exec "$@"
    ;;
esac
